import CodoBase from "../CodoBase";
import * as util from "util";
import { ListToTree } from "@diyaner/ding";
import { Application } from "egg";
import { ZKV6000 } from "./type.d";
import CodoError from "../CodoError";
import { md5 } from "../util";

/** 
 * 万傲瑞达，内置api，主要从前端探索来的，接口管理
 */
export default class ZKV6000InnerApiManager extends CodoBase {
	/** 请求的接口path */
	public urls = {
		login: "/login.do",
		persPerson: "/persPerson.do",
		/** 获取部门信息，应该是当前用户有权限的 */
		authDepartment: "/authDepartment.do",
		/** 离职保存接口 */
		personLeave: "/persLeavePerson.do?save",
	};
	/** 登录成功后存放sessionId */
	sessionId: string = "";

	constructor(protected app: Application, public config: ZKV6000.inner.ZKV6000InnerApiParams) {
		super(app);
	}

	/**
	 * 内置api登录万傲瑞达
	 * - experience: use this method two times , can get valid sessionid
	 *  */
	async login() {
		const user = this.config.username;
		const password = md5(this.config.password);
		const url = this.config.url + this.urls.login;
		const payload = {
			username: user,
			password,
		};

		let cookie = `SESSION=${this.sessionId}; menuType=text-only`;

		// return res2;
		const res = await this.app.curl<ZKV6000.inner.loginResponse>(url, {
			method: "post",
			data: payload,
			// content: `username=${payload.username}&password=${payload.password}`,
			dataType: "json",
			contentType: "application/x-www-form-urlencoded",
			followRedirect: true,
			rejectUnauthorized: false,
			headers: {
				"user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/113.0.0.0 Safari/537.36",
				"X-Requested-With": "XMLHttpRequest",

				host: this.config.url?.replace("http://", "").replace("https://", ""),
				Origin: this.config.url,
				cookie: cookie,
				connection: "keep-alive",
				Accept: "*/*",
				"Accept-Encoding": "gzip, deflate, br",
				"sec-ch-ua": `"Google Chrome";v="113", "Chromium";v="113", "Not-A.Brand";v="24"`,
				"Sec-Fetch-Dest": "empty",
				"Sec-Fetch-Mode": "cors",
				"sec-ch-ua-platform": "Windows",
				"sec-ch-ua-mobile": "?0",
				"Sec-Fetch-Site": "same-origin",
				"Cache-Control": "no-cache",
				Pragma: "no-cache",
			},
		});

		this.app.logger.debug("登录接口，获取header: \r\n %j", res.headers);
		if (res.status !== 200) {
			throw new CodoError(`登录出错，status非200！`);
		}

		const { data } = res;
		this.app.logger.debug(`登录结果：%j`, data);
		if (data.success) {
			const cookie = res?.headers?.["set-cookie"]?.[0] || null;
			if (cookie) {
				let a = cookie as string;
				this.app.logger.info("登录接口获取的cookie \r\n%s", a);
				// 正则表达式取出session
				const reg = /SESSION\=\s*(.*?)\s*\;/i;
				const execResult = reg.exec(a);
				if (execResult) {
					this.sessionId = execResult[1];
				}
			}
			if (!this.sessionId) {
				throw new CodoError(`登录出错，未获取到sessionId！`);
			}
			// return res.headers["set-cookie"];
			return res;
		} else {
			throw new CodoError(`登录出错 %s %s`, data.ret, data.msg);
		}
	}

	/**  查询人员列表
	 * - 返回原始格式的
	 */
	async getPersonList(size: number = 50, index: number = 1, moreOptions?: { pin?: string; deptName?: string; likeName?: string }) {
		if (!this.sessionId) throw new Error(`无cookie，请先登录！`);
		const url = this.config.url + this.urls.persPerson;
		moreOptions = moreOptions || {};
		const payload = {
			pageSize: size,
			posStart: (index - 1) * size,
			count: size,
			list: "",
			...moreOptions,
		};
		// const queryString = `list=&pageSize=${payload.pageSize}&sortName=&sortOrder=&posStart=${payload.posStart}&count=${payload.count}`;

		let cookie = `SESSION=${this.sessionId}; menuType=text-only`;
		// cookie = `menuType=text-only; SESSION=NDdiNjg3OWUtNWE4My00OTI2LWE1Y2UtOTJhODQ1NWE3ZTZl`;
		this.app.logger.debug(`请求人员列表时使用的cookie %s`, cookie);
		const res = await this.app.curl<ZKV6000.inner.getListCommonResponse>(url, {
			method: "POST",
			dataType: "json",
			contentType: "application/x-www-form-urlencoded",
			rejectUnauthorized: false,

			data: payload,
			headers: {
				cookie: cookie,
			},
			timeout: 10000,
		});

		// console.log(res);

		if (res.status !== 200) {
			this.app.logger.error(`查询列表出错，status非200，%s \r\n SESSION: %s`, res.status, this.sessionId);
			throw new CodoError(`查询列表出错，status非200！${res.status}`);
		}

		const { data } = res;
		// console.log(data);
		if (data.total_count && data.total_count >= 0) {
			return data;
		} else {
			const msg = util.format(`查询列表出错`);
			this.app.logger.error(`${msg} \r\n%j`, data);
			throw new CodoError(msg);
		}
	}

	/**
	 * 查询人员列表
	 * - 返回对象格式的，处理好的
	 */
	async getPersonObjectList(size: number = 50, index: number = 1, moreOptions?: { pin?: string; deptName?: string; likeName?: string }) {
		const res = await this.getPersonList(size, index, moreOptions);
		return {
			origin: res,
			list: res.rows.map((item) => {
				return this.parsePersonObject(item.data, item.id);
			}),
		};
	}

	/**  查询部门列表
	 * - 返回原始格式的
	 */
	async getDepartmentList(size: number = 50, index: number = 1) {
		if (!this.sessionId) throw new Error(`无cookie，请先登录！`);
		const url = this.config.url + this.urls.authDepartment;
		const payload = {
			pageSize: size,
			posStart: (index - 1) * size,
			count: size,
			list: "",
		};
		// const queryString = `list=&pageSize=${payload.pageSize}&sortName=&sortOrder=&posStart=${payload.posStart}&count=${payload.count}`;

		let cookie = `SESSION=${this.sessionId}; menuType=text-only`;
		// cookie = `menuType=text-only; SESSION=NDdiNjg3OWUtNWE4My00OTI2LWE1Y2UtOTJhODQ1NWE3ZTZl`;
		this.app.logger.debug(`请求部门列表时使用的cookie %s`, cookie);
		const res = await this.app.curl<ZKV6000.inner.getListCommonResponse>(url, {
			method: "POST",
			dataType: "json",
			contentType: "application/x-www-form-urlencoded",
			rejectUnauthorized: false,

			data: payload,
			headers: {
				cookie: cookie,
			},
			timeout: 10000,
		});

		// console.log(res);

		if (res.status !== 200) {
			this.app.logger.error(`查询部门列表出错，status非200，%s \r\n SESSION: %s`, res.status, this.sessionId);
			throw new CodoError(`查询列表出错，status非200！${res.status}`);
		}

		const { data } = res;
		// console.log(data);
		if (data.total_count && data.total_count >= 0) {
			return data;
		} else {
			const msg = util.format(`查询部门列表出错`);
			this.app.logger.error(`${msg} \r\n%j`, data);
			throw new CodoError(msg);
		}
	}

	/**  封装通用请求万傲瑞达方法 */
	async request<T extends any>(url: string, data: any, requestOptions?: Parameters<Application["curl"]>[1]): Promise<T> {
		if (!this.sessionId) throw new Error(`无cookie，请先登录！`);
		url = this.config.url + url;
		let cookie = `SESSION=${this.sessionId}; menuType=text-only`;

		const options = requestOptions || {};
		const defaultOptions: Parameters<Application["curl"]>[1] = {
			method: "POST",
			dataType: "json",
			contentType: "application/x-www-form-urlencoded",
			rejectUnauthorized: false,
			data: data,
			headers: {
				cookie: cookie,
			},
			timeout: 10000,
		};
		Object.assign(defaultOptions, options);
		const res = await this.app.curl<T>(url, {
			...defaultOptions,
		});

		if (res.status !== 200) {
			this.app.logger.error(`请求出错，status非200，%s \r\n SESSION: %s`, res.status, this.sessionId);
			throw new CodoError(`请求 %s 出错，status非200，${res.status}`, url);
		}
		return res.data;
	}

	/**
	 * 解析查询结果（一个数组）到一个对象
	 *
	 * - 将根据配置参数 departmentMaping 来做映射
	 */
	parseDepartmentObject(row: any[], id: string): ZKV6000.inner.departmentObject {
		if (!Array.isArray(this.config.departmentMapping) || this.config.departmentMapping.length < 1) throw new CodoError(`部门数组映射到对象，无映射配置`);
		const obj = { id } as ZKV6000.inner.departmentObject;
		this.config.departmentMapping.forEach((key, index) => {
			if (!key) return;
			obj[key] = row[index];
		});
		// @ts-ignore
		obj.parentCode = obj.parentCode || "-0";
		return obj;
	}

	/** 解析查询结果（一个数组）到一个对象
	 *
	 * - 将根据配置参数 personMaping 来做映射
	 */
	parsePersonObject(row: any[], id: string): ZKV6000.inner.personObject {
		if (!Array.isArray(this.config.personMapping) || this.config.personMapping.length < 1) throw new CodoError(`人员信息数组映射到对象，无映射配置`);

		const obj = { id } as ZKV6000.inner.personObject;
		this.config.personMapping.forEach((key, index) => {
			if (!key) return;
			obj[key] = row[index];
		});

		return obj;
	}

	/**
	 * 从万傲瑞达获取所有部门
	 * - 递归获取所有部门，返回处理好的对象数组
	 */
	async getAllDepartment(index = 1): Promise<ZKV6000.inner.departmentObject[]> {
		const data = await this.getDepartmentList(50, index);
		const { rows } = data;
		// 递归出口，如果没有更多部门，则不再继续递归查询。
		if (rows.length === 0) return [];
		const res = await this.getAllDepartment(++index);
		const list: ZKV6000.inner.departmentObject[] = [];
		for (const row of rows) {
			list.push(this.parseDepartmentObject(row.data, row.id));
		}
		return [...list, ...res];
	}

	/**
	 * 将部门列表转成树形结构
	 */
	getDepartmentTree(list: ZKV6000.inner.departmentObject[]) {
		const ltt = ListToTree.init(list);
		const tree = ltt.toTree({
			mapToLabel: "name",
			id: "code",
			rootValue: "-0",
			parent: "parentCode",
		});
		return { tree, ltt };
	}

	/** todo */
	// async leavePersons() {}

	/** 此id为db的id，不是pin */
	async getPersonPhoto(id: string) {
		if (!this.sessionId) throw new Error(`无cookie，请先登录！`);
		const url = this.config.url + this.urls.persPerson + "?edit=&id=" + id;
		let cookie = `SESSION=${this.sessionId}; menuType=text-only`;

		const res = await this.app.curl<string>(url, {
			method: "POST",
			dataType: "text",
			contentType: "application/x-www-form-urlencoded",
			rejectUnauthorized: false,
			data: {},
			headers: {
				cookie: cookie,
			},
			timeout: 10000,
		});

		// console.log(res.data);

		if (res.status !== 200 || !res.data) {
			this.app.logger.error(`获取人员照片出错，status非200，%s \r\n SESSION: %s`, res.status, this.sessionId);
			throw new CodoError(`获取人员照片出错，status非200，${res.status}`);
		}
		const htmlStr = res.data;

		//截取出base64的照片字符串
		const reg = /<img id="id_img_pers"\s+[^>]*src="([^"]*)"/gi;
		const match = htmlStr.match(reg);
		// console.log(match);
		if (match && match.length === 1) {
			const theStr1 = match[0];
			if (!theStr1) return "";
			const theStr2 = theStr1.split('src="')?.[1] || "";
			// console.log(theStr2);
			return theStr2?.substring(0, theStr2.length - 1) || "";
		}
		return "";

		// const { data } = res;
	}
}
